package com.xuecheng.search.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CoursePubIndexDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CoursePubIndexVo;
import com.xuecheng.commons.model.vo.CoursePubVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.search.domain.CoursePubIndex;
import com.xuecheng.search.service.SearchService;
import com.xuecheng.web.exception.BusinessException;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ContentClient contentClient;//课程feign

    @Autowired
    private RestHighLevelClient client;//es客户端

    @Override
    public void mysqlToEs(Long coursePubId) throws Exception{
        //根据课程发布id获取课程发布对象
        ResponseResult<CoursePubVo> responseResult = contentClient.findById(coursePubId);
        //判断是否调用失败
        if (responseResult.getCode()!=0){
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        //取出课程发布对象
        CoursePubVo coursePubVo = responseResult.getData();
        //vo转为es索引实体
        CoursePubIndex coursePubIndex = BeanHelper.copyProperties(coursePubVo, CoursePubIndex.class);
        coursePubIndex.setIs_pub(coursePubVo.getIsPub());//是否发布
        coursePubIndex.setCourse_id(coursePubVo.getCourseId());//课程id
        coursePubIndex.setIs_latest(coursePubVo.getIsLatest());//是否最新课程
        coursePubIndex.setCreate_date(new Date());//创建时间
        coursePubIndex.setCompany_id(coursePubVo.getCompanyId());//机构id
        coursePubIndex.setCompany_name(coursePubVo.getCompanyName());//机构名称
        coursePubIndex.setChange_date(new Date());//修改时间
        coursePubIndex.setComment_num(0L);//评论数
        coursePubIndex.setPrice(coursePubVo.getPrice().floatValue()*100);//设置价格 单位为分
        //写入es索引库
        //创建IndexRequest
        IndexRequest request = new IndexRequest("course").id(coursePubIndex.getId().toString());
        //构造条件
        request.source(JSON.toJSONString(coursePubIndex), XContentType.JSON);
        //发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

    //条件分页查询
    @Override
    public ResponseResult<CoursePubIndexVo> search(PageRequest pageRequest, CoursePubIndexDto coursePubIndexDto) throws IOException {
        //创建SearchRequest
        SearchRequest request = new SearchRequest("course");
        //构造dsl 使用布尔条件查询
        buildDsl(pageRequest, coursePubIndexDto, request);
        //发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析结果
        return getResponseResult(response);
    }

    //数据库删除同步至es
    @Override
    public void mysqlDeleteToEs(Long courseId) throws IOException {
        //创建DeleteRequest
        DeleteRequest request = new DeleteRequest("course", courseId.toString());
        //发送请求
        client.delete(request,RequestOptions.DEFAULT);
    }

    //根据id查询课程
    @Override
    public ResponseResult<CoursePubIndexVo> findById(String id) throws IOException {
        //创建GetRequest
        GetRequest request = new GetRequest("course").id(id);
        //发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //解析response
        String json = response.getSourceAsString();
        //json转vo
        CoursePubIndexVo coursePubIndexVo = JSON.parseObject(json, CoursePubIndexVo.class);
        return ResponseResult.okResult(coursePubIndexVo);
    }

    //解析response结果
    private ResponseResult getResponseResult(SearchResponse response) {
        //取出命中结果
        SearchHits hits = response.getHits();
        //取出总记录数
        long total = hits.getTotalHits().value;
        //取出总记录
        SearchHit[] searchHits = hits.getHits();
        //声明结果vo集合
        List<CoursePubIndexVo> voList = new ArrayList<>();
        if (ArrayUtil.isNotEmpty(searchHits)){
            for (SearchHit searchHit : searchHits) {
                //获取json
                String json = searchHit.getSourceAsString();
                //json转vo
                CoursePubIndexVo coursePubIndexVo = JSON.parseObject(json, CoursePubIndexVo.class);
                //指定indexId
                coursePubIndexVo.setIndexId(coursePubIndexVo.getCourseId());
                //高亮处理
                //取出高亮部分map集合
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                //非空判断
                if (CollectionUtil.isNotEmpty(highlightFields)){
                    //取出高亮字段数组
                    HighlightField nameArray = highlightFields.get("name");
                    if (nameArray!=null){
                        String name = nameArray.getFragments()[0].toString();
                        //vo设置高亮字段
                        coursePubIndexVo.setName(name);
                    }
                }
                //加入集合
                voList.add(coursePubIndexVo);
            }
        }
        return PageResponseResult.okResult(total, voList);
    }

    //构造dsl
    private void buildDsl(PageRequest pageRequest, CoursePubIndexDto coursePubIndexDto, SearchRequest request) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //根据关键字查询
        if (StrUtil.isNotEmpty(coursePubIndexDto.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("all", coursePubIndexDto.getKeyword()));
        }else {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //条件过滤
        if (StrUtil.isNotEmpty(coursePubIndexDto.getMt())){
            boolQuery.filter(QueryBuilders.termQuery("mt", coursePubIndexDto.getMt()));//大分类
        }
        if (StrUtil.isNotEmpty(coursePubIndexDto.getSt())){
            boolQuery.filter(QueryBuilders.termQuery("st", coursePubIndexDto.getSt()));//小分类
        }
        if (StrUtil.isNotEmpty(coursePubIndexDto.getGrade())){
            boolQuery.filter(QueryBuilders.termQuery("grade", coursePubIndexDto.getGrade()));//等级
        }
        request.source().query(boolQuery);
        //分页
        Integer pageNo = pageRequest.getPageNo();
        Integer pageSize = pageRequest.getPageSize();
        Integer index=(pageNo -1 ) * pageSize;
        request.source().from(index).size(pageSize);
        //高亮显示
        request.source().highlighter(new HighlightBuilder()
                .field("name")//对name字段高亮
                .preTags("<font style='color:red'>")
                .postTags("</font>")
                .requireFieldMatch(false));//取消字段匹配
    }
}
